﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace Slwy.JwtAuth
{
    public class JwtTools
    {
        /// <summary>
        /// 密匙Key，不能泄露！！！！
        /// </summary>
        private readonly static string signKey = "fda5124447b62ca332aa7177c799041d51bkajskwa";

        /// <summary>
        /// 设置JwtToken
        /// </summary>
        /// <param name="payload">the payload . </param>
        /// <returns>返回token</returns>
        public static string GetJwtToken(MJwtPayload payload)
        {
            if (payload == null)
            {
                return string.Empty;
            }

            if (string.IsNullOrWhiteSpace(payload.Exp))
            {
                payload.Exp = DateTime.Now.AddMinutes(2).ToString("yyyyMMddHHmmss"); // 过期时间 2分钟
            }

            payload.Iat = DateTime.Now.ToString("yyyyMMddHHmmss");

            if (string.IsNullOrWhiteSpace(payload.Aud))
            {
                payload.Aud = "slwy";
            }

            if (string.IsNullOrWhiteSpace(payload.UID))
            {
                return string.Empty;
            }

            payload.UID = EncryptUID(payload.UID); // 加密下UID

            payload.DeptID = EncryptUID(payload.DeptID); // 加密部门ID

            payload.CompanyID = EncryptUID(payload.CompanyID); // 加密公司ID

            // header
            MJwtHeader jwtHeader = new MJwtHeader();
            string strHeader = JsonConvert.SerializeObject(jwtHeader);
            byte[] headerDataBytes = Encoding.GetEncoding("utf-8").GetBytes(strHeader);
            string base64Header = Convert.ToBase64String(headerDataBytes);

            // payload
            string jwtPayload = JsonConvert.SerializeObject(payload);
            byte[] dataBytes = Encoding.GetEncoding("utf-8").GetBytes(jwtPayload);
            string base64Payload = Convert.ToBase64String(dataBytes);

            // sign
            string strSign = string.Join(".", base64Header, base64Payload);
            strSign += signKey;
            string jwtSign = SHA512Encrypt(strSign);

            string jwtToken = string.Join(".", base64Header, base64Payload, jwtSign);

            return jwtToken;
        }

        /// <summary>
        /// 不验证，直接把jwtToken转换成model
        /// </summary>
        /// <param name="jwtToken">jwttoken字符串</param>
        /// <returns>返回Model</returns>
        public static MJwtPayload GetJwtPayload(string jwtToken) {

            MJwtPayload payload = null;
            if (string.IsNullOrWhiteSpace(jwtToken))
            {
                return payload;
            }

            // 1、验证签名
            List<string> list = jwtToken.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (list.Count != 3)
            {
                return payload;
            }

            // 解析内容
            string strPayload = list[1];
            strPayload = Encoding.UTF8.GetString(Convert.FromBase64String(strPayload));
            payload = JsonConvert.DeserializeObject<MJwtPayload>(strPayload);
            long expTiem = long.Parse(payload.Exp);
            long currentTime = long.Parse(DateTime.Now.ToString("yyyyMMddHHmmss"));
            if (expTiem < currentTime)
            {
                return null;
            }

            payload.UID = DecryptUID(payload.UID);
            payload.DeptID = DecryptUID(payload.DeptID);
            payload.CompanyID = DecryptUID(payload.CompanyID);
            return payload;
        }

        /// <summary>
        /// 验证jwttoken
        /// </summary>
        /// <param name="jwtToken">字符串</param>
        /// <returns>验证失败返回false,验证成功返回true</returns>
        public static bool ValidateJwtToken(string jwtToken)
        {
            if (string.IsNullOrWhiteSpace(jwtToken))
            {
                return false;
            }

            // 1、验证签名
            List<string> list = jwtToken.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (list.Count != 3)
            {
                return false;
            }

            string payloadHeader = string.Join(".", list[0], list[1]);
            string strSign = SHA512Encrypt(payloadHeader + signKey);
            if (strSign != list[2])
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 加密用户ID
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        private static string EncryptUID(string uid)
        {
            if (string.IsNullOrWhiteSpace(uid))
            {
                return string.Empty;
            }

            Random random = new Random();
            string randomValue = random.Next(900).ToString().PadLeft(3, '0'); // 随机数

            // 使用uid最后一位数字，放置到该索引后面
            int index = random.Next(9);
            if (index > uid.Length)
            {
                index = uid.Length - 1;
            }

            uid = uid.Insert(index, randomValue);
            uid += index.ToString(); // 把随机的索引位置放置最后一位，用于解码
            return uid;
        }

        /// <summary>
        /// 解密UID
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        private static string DecryptUID(string uid)
        {
            if (string.IsNullOrWhiteSpace(uid))
            {
                return string.Empty;
            }

            // 获取UID最后一位
            string lastIndexValue = uid.Substring(uid.Length - 1, 1);
            int index = int.Parse(lastIndexValue);

            // 移除加的随机码的3位
            uid = uid.Remove(index, 3);
            uid = uid.Substring(0, uid.Length - 1);
            return uid;
        }

        /// <summary>
        /// 获取大写的MD5签名结果 
        /// </summary>
        /// <param name="encypStr">encypStr</param>
        /// <param name="charset">charset</param>
        /// <returns>返回结果</returns>
        private static string SHA512Encrypt(string encypStr, string charset = "UTF-8")
        {
            string retStr;
            MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();

            ////创建md5对象
            byte[] inputBye;
            byte[] outputBye;

            ////使用GB2312编码方式把字符串转化为字节数组．
            try
            {
                inputBye = Encoding.GetEncoding(charset).GetBytes(encypStr);
            }
            catch
            {
                inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
            }

            outputBye = m5.ComputeHash(inputBye);

            retStr = System.BitConverter.ToString(outputBye);
            retStr = retStr.Replace("-", string.Empty).ToUpper();
            return retStr;
        }
    }
}
